/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/jsf/trunk/jsf-app/src/java/org/sakaiproject/jsf/app/SakaiViewHandlerWrapper.java $ * $Id: SakaiViewHandlerWrapper.java 128959 2013-08-23 00:01:46Z ottenhoff@longsight.com $ ********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.jsf.app; import java.io.IOException; import java.util.Locale; import javax.faces.FacesException; import javax.faces.application.ViewHandler; import javax.faces.application.ViewHandlerWrapper; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.util.Web; /** * <p> * SakaiViewHandlerWrapper extends the basic ViewHandlerWrapper functionality * * @author University of Murcia * @version $Revision: 128959 $ */ public class SakaiViewHandlerWrapper extends ViewHandlerWrapper { // TODO: Note, these two values must match those in jsf-tool's JsfTool /** Request attribute we set to help the return URL know what path we add (does not need to be in the URL. */ public static final String URL_PATH = "sakai.jsf.tool.URL.path"; /** Request attribute we set to help the return URL know what extension we (or jsf) add (does not need to be in the URL. */ public static final String URL_EXT = "sakai.jsf.tool.URL.ext"; /** Our log (commons). */ private static Log M_log = LogFactory.getLog(SakaiViewHandler.class); /** The wrapped ViewHandler. */ private ViewHandler m_wrapped = null; /** Resource bundle using current language locale. */ private ResourceLoader rb; public SakaiViewHandlerWrapper(ViewHandler wrapped) { m_wrapped = wrapped; rb = new ResourceLoader(); } @Override public ViewHandler getWrapped() { return m_wrapped; } public String getActionURL(FacesContext context, String viewId) { HttpServletRequest req = (HttpServletRequest) context.getExternalContext().getRequest(); if (req.getAttribute(URL_EXT) == null) { // If the request didn't go through JsfTool (the JSF is accessed directly from its webapp, // not as a Sakai tool), then don't do Sakai's special action URL handling. return getWrapped().getActionURL(context, viewId); } // get the path that got us here (from the tool's point of view) String path = viewId; // modify the path to remove things that were added by Sakai navigation to get here (prefix path, suffix extension) String prefix = (String) req.getAttribute(URL_PATH); if ((prefix != null) && path.startsWith(prefix)) path = path.substring(prefix.length()); Object extensions = req.getAttribute(URL_EXT); String [] exts = extensions instanceof String?new String[]{(String)extensions}:(String[])extensions; for (String ext:exts) { if ((ext != null) && path.endsWith(ext)) path = path.substring(0, path.length() - ext.length()); } // make sure the URL processing uses the Sakai, not Native the request object so we can get at the URL information setup by the invoker req.removeAttribute(Tool.NATIVE_URL); // form our return URL String rv = Web.returnUrl(req, path); // restore (if needed) req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL); M_log.debug("action url for view: " + viewId + " = " + rv); return rv; } /** Methods delegated to default ViewHandler */ public Locale calculateLocale(FacesContext arg0) { return rb.getLocale(); } public String calculateRenderKitId(FacesContext arg0) { return getWrapped().calculateRenderKitId(arg0); } public UIViewRoot createView(FacesContext arg0, String arg1) { UIViewRoot root = getWrapped().createView(arg0, arg1); if (root != null) { // restore messages MessageSaver.restoreMessages(arg0); } return root; } public String getResourceURL(FacesContext arg0, String arg1) { return getWrapped().getResourceURL(arg0, arg1); } public void renderView(FacesContext context, UIViewRoot root) throws IOException, FacesException { // SAK-20286 start // Get the request HttpServletRequest req = (HttpServletRequest) context.getExternalContext().getRequest(); String requestURI = req.getRequestURI(); // Make the attribute name unique to the request String attrName = "sakai.jsf.tool.URL.loopDetect.viewId-" + requestURI; // Try to fetch the attribute Object attribute = req.getAttribute(attrName); // If the attribute is null, this is the first request for this view if (attribute == null) { req.setAttribute(attrName, "true"); } else if ("true".equals(attribute)) { // A looping request is detected. HttpServletResponse res = (HttpServletResponse) context.getExternalContext().getResponse(); // Send a 404 res.sendError(404, "File not found: " + requestURI); } // SAK-20286 end getWrapped().renderView(context, root); } public UIViewRoot restoreView(FacesContext arg0, String arg1) { UIViewRoot root = getWrapped().restoreView(arg0, arg1); if (root != null) { // restore messages MessageSaver.restoreMessages(arg0); } return root; } public void writeState(FacesContext arg0) throws IOException { getWrapped().writeState(arg0); } }